/*
 * JoinComponentDefinition.java
 *
 * Created on September 27, 2006, 11:37 PM
 *
 * (C) 2006 R. Alexander Milowski
 */

package com.smallx.xproc.library;

import com.smallx.xproc.ComponentType;
import java.net.URI;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import org.infoset.component.Component;
import org.infoset.component.ComponentBase;
import org.infoset.component.ComponentDefinition;
import org.infoset.xml.Document;
import org.infoset.xml.Item;
import org.infoset.xml.ItemDestination;
import org.infoset.xml.Name;
import org.infoset.xml.XMLException;
import org.infoset.xml.util.DocumentSource;

/**
 *
 * @author alex
 */
public class JoinComponentDefinition implements ComponentDefinition {

   static ComponentType defaultType = new ComponentType(LibraryComponents.JOIN_TYPE);
   static {
      defaultType.addInputPort(Name.create("input"),true);
      defaultType.setArbitraryOutputs(true);
   }
   protected ComponentType type;
   
   public JoinComponentDefinition() {
      this(defaultType);
   }
   /** Creates a new instance of FlowComponentDefinition */
   public JoinComponentDefinition(ComponentType type) {
      this.type = type;
   }
   
   public Component newInstance()
      throws XMLException 
   {
      return new ComponentBase(type.getName()) {
         List<ItemDestination> destinations;
         public void init(Component.Context context) 
            throws XMLException
         {
            destinations = new ArrayList<ItemDestination>();
         }
         public void bindOutputPort(Name port,ItemDestination dest) 
            throws XMLException
         {
            if (!type.hasArbitraryOutputs() && type.getOutputPort(port)==null) {
               throw new XMLException("There is no output port named "+port+" on the pipeline "+type.getName());
            }
            destinations.add(dest);
         }

         public void onStart()
            throws XMLException
         {
         }

         public ItemDestination getInputPort(Name port) 
            throws XMLException
         {
            Name inputName = type.getInputPortNames().iterator().next();
            if (!port.equals(inputName)) {
               throw new XMLException("There is no input port named "+port+" on the pipeline "+type.getName());
            }
            return new ItemDestination() {
               public void send(Item item)
                  throws XMLException
               {
                  for (ItemDestination dest : destinations) {
                     dest.send(item.copyOfItem(false));
                  }
               }
            };
         }

         public void onDocumentInput(Name port,Document doc) 
            throws XMLException
         {
            Name inputName = type.getInputPortNames().iterator().next();
            if (!port.equals(inputName)) {
               throw new XMLException("There is no input port named "+port+" on the pipeline "+type.getName());
            }
            for (ItemDestination dest : destinations) {
               DocumentSource.generate(doc,false,dest);
            }
         }

         public void onEnd()
            throws XMLException
         {
         }

      };
   }
      
   public Name getName() {
      return type.getName();
   }

   public String getVersion() {
      return null;
   }

   public String getVendor() {
      return null;
   }

   public URI getVendorLocation() {
      return null;
   }

   public Collection<Name> getInputs() {
      return type.getInputPortNames();
   }

   public Collection<Name> getOutputs() {
      return type.getOutputPortNames();
   }

}

